#pragma once

#include <cstring>
#include <string>
#include <mutex>
#include <fstream>

namespace exclog
{
    constexpr const char *strrchr(const char *s, const char c_in)
    {
        const char *found = NULL;

        for (;;)
        {
            if (*s == c_in)
                found = s;
            if (*s++ == '\0')
                break;
        }

        return found;
    }

    template <int N>
    struct StringLiteral
    {
        char data[N] = {0};

        constexpr StringLiteral(const char (&str)[N])
        {
            const char *findE = exclog::strrchr(str, '/');
            if (findE)
            {
                findE++;
                for (int i = 0; i < N && *findE != '\0'; i++, findE++)
                    data[i] = *findE;
            }
            else
            {
                for (int i = 0; i < N; i++)
                    data[i] = str[i];
            }
        }

        constexpr const char *c_str() const { return data; }
    };

    extern bool isdebug;
    extern std::mutex s_logMutex;
    extern std::string logpath;

    inline void getEnvLog()
    {
        char *env = getenv("ZUT_LOG");
        if (env != NULL)
            isdebug = true;
        else
            isdebug = false;
    }

    inline void printfCurrentTime()
    {
        std::ofstream file(exclog::logpath, std::ios::app);

        struct timespec ts;
        clock_gettime(CLOCK_REALTIME, &ts);
        time_t sec = ts.tv_sec;
        long msec = ts.tv_nsec / 1000000;
        struct tm *local = localtime(&sec);
        char time_str[20];
        strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", local);
        printf("%s.%03ld ", time_str, msec);

        char logBuffer[1024] = "";
        snprintf(logBuffer, sizeof(logBuffer), "%s.%03ld ", time_str, msec);
        file << logBuffer;
        
        file.close();
    }

}; // namespace exclog

#define getFileName(VRNAME) constexpr exclog::StringLiteral<(sizeof(__BASE_FILE__))> VRNAME(__BASE_FILE__)

#define LOG(fmt, ...)                                                                                               \
    do                                                                                                              \
    {                                                                                                               \
        if (exclog::isdebug)                                                                                        \
        {                                                                                                           \
            std::ofstream file(exclog::logpath, std::ios::app);                                                     \
            std::lock_guard<std::mutex> l(exclog::s_logMutex);                                                      \
            exclog::printfCurrentTime();                                                                            \
            getFileName(__strLog);                                                                                  \
            printf("<%s::%s> " fmt, __strLog.c_str(), __FUNCTION__, ##__VA_ARGS__);                                 \
            printf("\n");                                                                                           \
            char logBuffer[1024] = "";                                                                              \
            snprintf(logBuffer, sizeof(logBuffer), "<%s::%s> " fmt, __strLog.c_str(), __FUNCTION__, ##__VA_ARGS__); \
            file << logBuffer << "\n";                                                                              \
            file.close();                                                                                           \
        }                                                                                                           \
    } while (0)

#define DEFINE_UT_DEBUG            \
    bool exclog::isdebug;          \
    std::mutex exclog::s_logMutex; \
    std::string exclog::logpath;

// eof